#ifndef _OH_CMD_H
#define	_OH_CMD_H
/*******************************************************************************
 ** Name: cmd.h                                                               **
 ** Description:                                                              **
 **                                                                           **
 ** Open Source Initiative (OSI) Approved 2-clause BSD License                **
 **                                                                           **
 **  Copyright (c) 2009-2010 Barry "Gian" James  <bjames@munixos.net>         **
 **  All rights reserved.                                                     **
 **                                                                           **
 **  Redistribution and use in source and binary forms, with or without       **
 **  modification, are permitted provided that the following conditions are   **
 **  met:                                                                     **
 **                                                                           **
 **  * Redistributions of source code must retain the above copyright notice, **
 **    this list of conditions and the following disclaimer.                  **
 **  * Redistributions in binary form must reproduce the above copyright      **
 **    notice, this list of conditions and the following disclaimer in the    **
 **    documentation and/or other materials provided with the distribution.   **
 **                                                                           **
 **  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS      **
 ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED **
 ** TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A           **
 ** PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT        **
 ** HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,    **
 ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED  **
 ** TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR    **
 ** PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF    **
 ** LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING      **
 ** NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS        **
 ** SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.              **
 **                                                                           **
 ******************************************************************************/
// Modified $Date: 2011-09-18 21:48:59 +0000 (Sun, 18 Sep 2011) $ by $Author: gian.james $
#define cmd_h_ID    "$Id: cmd.hpp 145 2011-09-18 21:48:59Z gian.james $"

extern "C" {
#include <stdarg.h>
}
#include <iostream>
#include <boost/intrusive/splay_set.hpp>
#include <boost/algorithm/string.hpp>
#include <boost/functional/hash.hpp>

#include <string>
#include <vector>
#include <queue>

#include "common.hpp"
#include "nlp.hpp"
#include "object.hpp"
#include "client.hpp"
#include "visitor.hpp"

#define MAX_CMD_ARGS    8

// Command permission and other flags
#define CMD_CONTROL	0x0001	// game/agency control
#define CMD_HANDLER	0x0002	// agent handler
#define CMD_BUILDER	0x0004	// world builder
#define CMD_SINGLETON	0x0008	// top-level agent
#define CMD_AGENT		0x0010	// regular any ol' agent
#define CMD_NPC		0x0020
#define CMD_WALL		0x0040
#define CMD_GUEST		0x0080
#define CMD_OWNER		0x0100
#define CMD_DISABLED	0x0200	// disabled command
#define CMD_INVISIBLE	0x0400	// cmd doesn't show up in any lists
#define CMD_DIRECTOR	0x0800	// the agency directors that set game policy
#define CMD_LOG		0x1000	// log the command

typedef uint16_t cmdFlags;

// TODO Should the following two function definitions take a client, socket fd,
// or Socket object as a parameter?
// direct obj, indirect obj, player(from), varargs
#define PREDDECL(NAME) CmdReturn pred_ ## NAME(WorldObject * dio, WorldObject * ido, Client * from,...)
#define CMDDECL(NAME) CmdReturn cmd_ ## NAME(WorldObject * dio, WorldObject * ido, Client * from,...)

enum class CmdReturnType { Error, Ok, OutOfBounds, DivideByZero, ArgCount,
	InsufficientLevel, InsufficientPrivs, Unknown };

struct CmdReturn
{
    CmdReturnType   ret;
};


class Cmd;

enum class CmdID : uint8_t {
	chelp, cquit, cstats, cinventory, cdossier, cskill,cmotd,

	max
};
enum class PredID : uint8_t {
	pput, ptake, pexamine, plook, psay, ptell, pshout,

	max
};
enum class CmdType { Client, Server, Command, Predicate };
enum class CmdCategory { ItemAction, Action, Knowledge, Information,
	Admin, Skill, Feat, Builder, Handler, Control, Agent, Communication,
	Movement, Combat, Character, System,
	max
};
// Merged predicate and commands into one for use in a splay tree lookup table
struct Command
{
//	Command();
	std::string		cmd;
	uint8_t			id;
	CmdType			type;
	CmdCategory		category;
	uint8_t			cost;
	flags16			permissions;
	std::vector<std::string>  *synonyms;
	std::string		errorMsg;
	CmdReturn		(Cmd::*cmdFunc)(WorldObject *,WorldObject *,Client *,...);
	// Help system
	std::string		syntax;
	std::string		example;
	std::string		desc;
	uint64_t		access;	// number of times accessed

	boost::intrusive::splay_set_member_hook<> member_hook_;
//	boost::intrusive::unordered_set_member_hook<> member_hook_;

	friend bool operator == (const Command &a, const Command &b)
		{ return boost::algorithm::iequals(a.cmd,b.cmd,std::locale()); }
	friend std::size_t hash_value(Command const &c)
		{ boost::hash<std::string> hasher; return hasher(c.cmd); }
	friend bool operator < (const Command &a, const Command &b)
	{ return (uint8_t)a.id < (uint8_t)b.id; }
	friend bool operator > (const Command &a, const Command &b)
	{ return (uint8_t)a.id > (uint8_t)b.id; }
};
using namespace boost::intrusive;
typedef member_hook<Command,splay_set_member_hook<>,&Command::member_hook_> memberOption;
//typedef splay_set<Command,compare<std::less<Command> >, memberOption> splaySet;
typedef splay_set<Command,memberOption> splaySet;

struct CmdQueueNode {
	std::string cmd;
	Client *	from;
};
// Our global enqueue function
void	Enqueue(CmdQueueNode &);
//extern std::queue<CmdQueueNode> cmdQueue;

//! Handles nlp commandline parsing and execution
class Cmd : public Pattern::Visitor
{
public:
    Cmd();
    Cmd(const Cmd& orig);
    virtual ~Cmd();

    // TODO not yet implemented
    virtual int visit(WorldObject *);
    /////////////[ commands
    // predicates
    PREDDECL(take);
    PREDDECL(put);
    PREDDECL(examine);
    PREDDECL(look);
    PREDDECL(open);
    PREDDECL(say);
    PREDDECL(tell);
    PREDDECL(get);		// syn for take
    PREDDECL(wear);
    PREDDECL(remove);	// unwear
    PREDDECL(wield);
    PREDDECL(unwield);
    PREDDECL(drop);
    PREDDECL(holster);
    PREDDECL(go);	// @Deprecated
    PREDDECL(north);
    PREDDECL(south);
    PREDDECL(east);
    PREDDECL(west);
    PREDDECL(up);
    PREDDECL(down);
    PREDDECL(n);
    PREDDECL(s);
    PREDDECL(e);
    PREDDECL(w);
    PREDDECL(u);
    PREDDECL(d);
    PREDDECL(shout);	// to all current users. maybe to be removed.
    PREDDECL(search);
    PREDDECL(enter);
    PREDDECL(sit);
    PREDDECL(jump);
    PREDDECL(leave);
    PREDDECL(close);
    PREDDECL(unlock);
    PREDDECL(lock);
    PREDDECL(ask);
    PREDDECL(cover);	// as in, take cover
    PREDDECL(push);
    PREDDECL(read);
    PREDDECL(throw);
    PREDDECL(wait);
    PREDDECL(show);
    PREDDECL(give);
    PREDDECL(listen);	// this might should be under a %skill
    PREDDECL(climb);
    PREDDECL(turn);		// as in "turn on light" "turn off light"
    PREDDECL(repair);
    PREDDECL(pick);		// as in "pick up screwdriver"
    PREDDECL(grab);
    PREDDECL(hold);
    PREDDECL(arrange);
    PREDDECL(recite);
    PREDDECL(cast);
    PREDDECL(equip);
    PREDDECL(crouch);
    PREDDECL(run);
    PREDDECL(stand);
    PREDDECL(rest);

    // commands
    CMDDECL(inventory);
     CMDDECL(skill);     //!< "%aimedshot <target>
     CMDDECL(dossier);
    CMDDECL(help);
    CMDDECL(consider);	// like 'examine <npc>' from nwn2
    CMDDECL(quit);
    CMDDECL(news);
    	// store/shop commands
    CMDDECL(buy);	// buy something
    CMDDECL(list);	// list of what's for sale
    CMDDECL(value);	// to get value of your item to sell
    CMDDECL(sell);	// sell an item
    CMDDECL(me);	// for /me emotes
    CMDDECL(train);
    CMDDECL(who);
    CMDDECL(whois);
    CMDDECL(draw);		// draw weapon
    CMDDECL(attack);	// this should be substituted for more specific feat/skill
    CMDDECL(assignments);
    CMDDECL(tasks);		// syn for assignments
    CMDDECL(account);	// get account info
    CMDDECL(coordinates);
    CMDDECL(effects);	// get current effects
    CMDDECL(friends);	// add friends to your friends list
    CMDDECL(cooldowns);	// any skills/feats on cooldown?
    CMDDECL(follow);	// follow another player
    CMDDECL(team);		// create a team
    CMDDECL(invite);	// invite to team
    CMDDECL(disband);	// disband team (need a more espionage way of saying this)
    CMDDECL(duel);		// pvp
    CMDDECL(recruit);	// recruit agent into agency
    CMDDECL(save);
    CMDDECL(spells);
    CMDDECL(mutant);
    CMDDECL(afk);
    CMDDECL(autoloot);
    CMDDECL(about);
    CMDDECL(motd);
    CMDDECL(faq);
    CMDDECL(socials);		// prefab emotes
    CMDDECL(bug);			// submit bug
    CMDDECL(idea);			// submit idea
    CMDDECL(call_control);
    CMDDECL(reghelper);		// register as a newbie helper
    CMDDECL(seen);
    CMDDECL(finger);

    // Game Control commands
    ///// maybe these object commands should all be consolidated under
    ///// one 'object' command?
//    CMDDECL(create_object);
//    CMDDECL(destroy_object);
//    CMDDECL(edit_object);
//    CMDDECL(chown_object);
//    CMDDECL(clone_object);
//    CMDDECL(examine_object);
    CMDDECL(object);
    ///// maybe consolidate these under 'client' command?
//    CMDDECL(disconnect_client);
//    CMDDECL(examine_client);
//    CMDDECL(get_client_passwd);
//    CMDDECL(set_client_passwd);
    CMDDECL(client);
    CMDDECL(passwd);	// change own password
    CMDDECL(giveitem);	// instantiate object and put in player's inventory
    ///// consolidate under 'npc' command
//    CMDDECL(create_npc);
//    CMDDECL(delete_npc);
//    CMDDECL(kill_npc);
    CMDDECL(npc);
    CMDDECL(shutdown);
    CMDDECL(reboot);
    ///// consolidate under 'channel' command
//    CMDDECL(create_channel);
//    CMDDECL(destroy_channel);
//    CMDDECL(edit_channel);
//    CMDDECL(channel_list);
//    CMDDECL(open_channel);
//    CMDDECL(close_channel);
    CMDDECL(channel);
    CMDDECL(mail);
    ///// consolidated under 'mail' command
//    CMDDECL(checkmail);
//    CMDDECL(sendmail);
//    CMDDECL(deletemail);
    CMDDECL(doing);
    ///// consolidated under 'dump' command
//    CMDDECL(dump_database);
    CMDDECL(dump); // db, stats, memory,
    CMDDECL(entrances);
    CMDDECL(history);
    CMDDECL(last);			// last login information
    CMDDECL(character);
    CMDDECL(profession);
    CMDDECL(background);
    CMDDECL(occupation);
    CMDDECL(trait);
    CMDDECL(feat);
    ///// consolidated under 'list' command
//    CMDDECL(list_table_names);		// internal
//    CMDDECL(list_queue_contents);	// internal message queue pump
    ///// consolidated under 'message' command
//    CMDDECL(list_messages);, commands
//    CMDDECL(delete_message);
//    CMDDECL(send_message);
//    CMDDECL(read_message);
//    CMDDECL(setmotd); 'motd set /path/to/motd'
    CMDDECL(wallop);	// to all operators/control/handlers
    CMDDECL(wall);		// to all users
    CMDDECL(stats);		// certain server/world statistics
    CMDDECL(teleport);
    CMDDECL(version);
    CMDDECL(log);		// log all activity/events from your console
    CMDDECL(emotes);
    CMDDECL(emoteto);
    CMDDECL(agency);	// info about the agency (and other agencies?)
    CMDDECL(uptime);	// an uptime facility
    CMDDECL(ignore);
    CMDDECL(describe);	// describes how others see you in brief
//    CMDDECL(showemotes);
    CMDDECL(users);		// users online now, max since boot, max ever, types
    CMDDECL(awards);	// show awards you and (others?) have won
    CMDDECL(ban);		// ban a user/ip/connection
    CMDDECL(locate);
    CMDDECL(bounty);	// look for jobs with bounties

    // world commands
    ///// consolidated under 'door' command
//    CMDDECL(link_door);
//    CMDDECL(unlink_door);
    CMDDECL(door);
    CMDDECL(room);
    CMDDECL(area);
    CMDDECL(load_script);
    ///// consolidated under 'area' command
//    CMDDECL(create_area);
//    CMDDECL(destroy_area);
//    CMDDECL(edit_area);
//    CMDDECL(examine_area);
    CMDDECL(module);	// load,unload,reload


    /////////////[ help commands
    void help(std::string);
    
    static Command * Commands() { return &commands[0]; }
    static Command * Predicates() { return &predicates[0]; }
    static bool     IsPrep(const char *);
    static bool     IsArticle(const char  *);
    static bool		IsPronoun(const char *);
    
    // Must call Init() before use;
    int				Init() { return BuildCmdTree(); }
    int				BuildCmdTree();
    int				ProcessQueue();

private:
    int  parse(std::string & cmd, Client * from);

    // We use a splay tree implementation here to exploit the splaying
    // effect of recently accessed members, pushing more recently and often
    // used commands toward the root of the tree for faster access
    splaySet 		cmdTree;

    static Command    predicates[];
    static Command		commands[];

    char *	argv[];	// argv[0] is cmd/pred. NULL always at end.
    int				argc;
};




#endif	/* _OH_CMD_H */

